#ifndef ___fuse_read
#define ___fuse_read 1

#ifndef FUSE_USE_VERSION
#define FUSE_USE_VERSION 28
#endif

#include <stdio.h>
#include <stdlib.h>
#include "mtlib.c"
#include <fuse.h>
#include <fcntl.h>
#include <errno.h>
#include "logging.c"

struct datosLeer {
  long long descriptor;
  char * buffer;
  char estado;
  long cantidad;
  long cantidadPartes;
};

//PROTOTIPOS
int fuse_read(const char *, char *, size_t, off_t, struct fuse_file_info *);
void ___fuse_procesar_mensaje_read(unsigned char, mti_mensaje, struct datosLeer *);

//LEER ARCHIVO
int fuse_read (const char * path, char * buffer, size_t size, off_t offset, struct fuse_file_info * ptr) {
//el kernel de linux cuando quiera leer un archivo me va a dar la posicion desde
//la cual tengo que empezar a leer para devolver el contenido

  int resultado;
  mti_mensaje datosMensaje;
  uint64_t descriptorArchivo;
  struct datosLeer datos;
  unsigned char centro_read = 0;
  unsigned int descriptorConexion;

  descriptorArchivo = ptr -> fh; // accedo al campo file handle de la estructura para tomar el descriptor del archivo

  datos.estado = 0;
  datos.buffer = buffer;
  datos.descriptor = descriptorArchivo;
  datos.cantidad = 0;

  while (centro_read == 0)
      centro_read = mtf_obtener_descriptor(1024);

  descriptorConexion = mtf_conectar(centro_read, MTP_INTERNO, centro_fat);

  if (descriptorConexion == 0) {
    mtf_liberar_descriptor(centro_read);
    return -EAGAIN;
  }
  
  resultado = mtf_enviar_mensaje(centro_read, descriptorConexion, MTE_LEER_ARCHIVO, (long) size, (long) offset,
                                  (long long) descriptorArchivo);
  //envio un mensaje al sistema fat para que me lea los datos de un archivo, para eso le paso el tamaÃƒÂ±o de los datos
  //a leer, la direccion y el descriptor del archivo obtenido antes cuando se abrio el archivo

  if (resultado == 0) {
    mtf_desconectar(centro_read, descriptorConexion);
    mtf_liberar_descriptor(centro_read);
    return -EAGAIN;
  }

  while (!datos.estado) {

    if (!mtf_recibir_mensajes(centro_read)) continue;

    datosMensaje = mtf_siguiente_mensaje(centro_read);
    ___fuse_procesar_mensaje_read(centro_read, datosMensaje, &datos);
    mtf_descartar_mensaje(centro_read, datosMensaje.codigo);
    
  }
  
  mtf_desconectar(centro_read, descriptorConexion); //desconecto la conexion del centro de mensajes
  mtf_liberar_descriptor(centro_read); //libero centro de mensajes con sus datos y conexiones

  switch (datos.estado) {
    // el estado es 255 si no hay error, o el motivo del error si lo hay
    case 1:
      return -EBADF; //el descriptor no existe
    case 2:
      return -EINVAL; //el archivo no existe
    case 3:
      return -EISDIR; //el descriptor representa un directorio
    case 4:
      return 0; //no se lee nada
    case 5:
      return -EBADF; //el descriptor no esta abierto para lectura
    default:
      return datos.cantidad; //retorno al kernel la cantidad de bytes leidos
  }
}

void ___fuse_procesar_mensaje_read (unsigned char centro_read, mti_mensaje datosMensaje, struct datosLeer * datosLectura) {

  long long descriptor;
  long cantidadPartes;
  
  if (datosMensaje.categoria != MTA_MENSAJE) return;

  switch (datosMensaje.tipo) {

    case MTE_NULL:

      mtf_enviar_mensaje(centro_read, datosMensaje.remitente, MTR_NULL);

    break;

    case MTR_NULL: case MTQ_MENSAJE_NO_VALIDO:

    break;

    case MTR_INICIO_DATOS_ARCHIVO:
    
      mtf_obtener_datos(centro_read, datosMensaje.codigo, (long long *) &descriptor, (long int *) &cantidadPartes);
      datosLectura -> cantidadPartes = cantidadPartes;
      break;
      
    case MTR_DATOS_ARCHIVO:
    
      {
      
        void * buffer = (datosLectura -> buffer) + (datosLectura -> cantidad);
        unsigned short tamano;

        mtf_obtener_datos(centro_read, datosMensaje.codigo,NULL, NULL, (unsigned short *) &tamano, (void **) &buffer);
        
        datosLectura -> cantidad += tamano;

      }
      break;

    case MTR_FIN_DATOS_ARCHIVO:
          
      log_registrar(descArch, "FUSE", LOG_INFO, "Se obtuvieron los datos del archivo");
      datosLectura -> estado = 255;
      break;

    case MTR_NO_LEYO_ARCHIVO:
    
      {
      
        char motivo;

        mtf_obtener_datos(centro_read, datosMensaje.codigo,NULL, (char *) &motivo);

        log_registrar(descArch, "FUSE", LOG_WARN, "No se obtuvo informacion del archivo (motivo: %hhu)", motivo);

        datosLectura -> estado = motivo;
      
      }
      break;
          
    default:

      mtf_enviar_mensaje(centro_read, datosMensaje.remitente, MTQ_MENSAJE_NO_VALIDO);

    break;
  
  }

}

#endif

